package com.gexada.simplechat.mvc;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.messaging.simp.annotation.SubscribeMapping;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.gexada.simplechat.data.ActiveWebSocketUserRepository;
import com.gexada.simplechat.data.ActiveWebSocketUserRole;
import com.gexada.simplechat.data.FriendShip;
import com.gexada.simplechat.data.FriendShipRepository;
import com.gexada.simplechat.data.InstantMessage;
import com.gexada.simplechat.data.InstantUser;
import com.gexada.simplechat.data.Message;
import com.gexada.simplechat.data.MessageRepository;
import com.gexada.simplechat.data.User;
import com.gexada.simplechat.security.CurrentUser;
import com.gexada.simplechat.util.UserRoleHelper;

/**
 * WebSocket 连接处理Controller
 *
 */
@Controller
public class MessageController {

	private Logger logger = LoggerFactory.getLogger(MessageController.class);
	private Logger chatHistoryLogger = LoggerFactory.getLogger("CHAT_HISTORY");

	private SimpMessageSendingOperations messagingTemplate;
	private ActiveWebSocketUserRepository activeUserRepository;
	private FriendShipRepository friendShipRepository;
	private MessageRepository messageRepository;

	@Autowired
	public MessageController(ActiveWebSocketUserRepository activeUserRepository,
			SimpMessageSendingOperations messagingTemplate, FriendShipRepository friendShipRepository,
			MessageRepository messageRepository) {
		this.activeUserRepository = activeUserRepository;
		this.messagingTemplate = messagingTemplate;
		this.friendShipRepository = friendShipRepository;
		this.messageRepository = messageRepository;
	}

	@RequestMapping("/")
	public String chat(@CurrentUser UserDetails userDetails) {
		Collection<? extends GrantedAuthority> roles = userDetails.getAuthorities();
		boolean isService = UserRoleHelper.isService(roles);
		return isService ? "service" : "customer";
	}

	@MessageMapping("/im")
	public void im(InstantMessage im, @CurrentUser User user) {

		im.setFrom(user.getEmail());

		Message msg = new Message(im);
		Message message = messageRepository.save(msg);
		im.setId(message.getId());

		if (chatHistoryLogger.isDebugEnabled()) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh24:mm:ss ssss");
			chatHistoryLogger.debug("[CHAT-MSG-ID " + im.getId() + "] " + im.getFrom() + " send message to " + im.getTo() + " at "
					+ sdf.format(im.getCreated().getTime()));
		}

		try {
			messagingTemplate.convertAndSendToUser(im.getFrom(), "/queue/messages", im);
			if (activeUserRepository.countByUsername(im.getTo()) > 0) {
				messagingTemplate.convertAndSendToUser(im.getTo(), "/queue/messages", im);
			}
		} catch (Exception e) {
			logger.warn("Error occured when " + im.toString(), e);
		}

	}

	@MessageMapping("/rm")
	public void rm(InstantMessage im) {

		if (chatHistoryLogger.isDebugEnabled()) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh24:mm:ss ssss");
			chatHistoryLogger.debug("[CHAT-MSG-ID " + im.getId() + "] " + im.getTo() + " received message from " + im.getFrom()
					+ " at " + sdf.format(new Date()));
		}

		Message msg = messageRepository.findOne(im.getId());
		msg.setRead(true);
		messageRepository.save(msg);
	}

	@SubscribeMapping("/history/{from}")
	public List<InstantMessage> subscribeMessageHistory(@DestinationVariable("from") String from,
			@CurrentUser User user) throws Exception {

		List<InstantMessage> history = new ArrayList<>();

		List<Message> messages = messageRepository.findAllByFromAndToAndIsRead(from, user.getEmail(), false);
		for (Message message : messages) {
			InstantMessage msg = new InstantMessage(message);
			history.add(msg);
		}
		return history;
	}

	@SubscribeMapping("/friends")
	public List<InstantUser> subscribeFriends(@CurrentUser User user) throws Exception {

		List<InstantUser> users = new ArrayList<>();

		List<FriendShip> friendShips = friendShipRepository.findByUser(user);
		for (FriendShip friendShip : friendShips) {
			InstantUser instantUser = buildInstantUser(user.getEmail(), friendShip.getFriend().getEmail());
			users.add(instantUser);
		}
		return users;
	}

	@SubscribeMapping("/organizations")
	public List<InstantUser> subscribeOrganizations(@CurrentUser User user) throws Exception {
		List<InstantUser> users = new ArrayList<>();

		List<String> activeUsers = activeUserRepository.findAllActiveUsersByRole(ActiveWebSocketUserRole.SERVICE);
		for (String activeUser : activeUsers) {
			InstantUser instanceUser = buildInstantUser(user.getEmail(), activeUser);
			users.add(instanceUser);
		}
		return users;
	}

	/**
	 * 创建InstantUser
	 * <p>
	 * 从 {@link #activeUserRepository} 中查找用户是否在线，从{@link #messageRepository}
	 * 中查找是否有未读消息
	 * 
	 * @param user
	 * @param friend
	 * @return
	 */
	private InstantUser buildInstantUser(String user, String friend) {
		InstantUser instantUser = new InstantUser();
		instantUser.setUsername(friend);
		int onlineCount = activeUserRepository.countByUsername(friend);
		instantUser.setOnline(onlineCount > 0);
		int messageCount = messageRepository.countByFromAndToAndIsRead(friend, user, false);
		instantUser.setMessageCount(messageCount);
		return instantUser;
	}
}